package com.erdos.common.web;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;

import com.erdos.common.entity.AbstractEntity;
import com.erdos.common.pagination.Page;
import com.erdos.common.service.AppServiceHelper;
import com.erdos.common.service.BaseService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * 基于Struts2的Action基类
 * 
 * @see Preparable
 * @see ModelDriven
 * @author xiali2
 */

public class BaseAction<T extends AbstractEntity> extends ActionSupport implements Preparable, ModelDriven<T> {

    public final static String PARAMS_KEY_PAGE_NO = "pn";

    public final static String PARAMS_KEY_PAGE_LIMIT = "limit";

    public final static String PARAMS_KEY_PAGE_OBJECT = "page";

    private static final long serialVersionUID = -7515581273533743583L;

    protected final static int PAGE_LIMIT = 10;

    public final static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";

    // 放置查询参数的Map对象
    private Map<String, String> qm = new HashMap<String, String>();

    // list页面定义
    public static final String LIST = "list";

    // logger for subclass
    private static final Log logger = LogFactory.getLog(BaseAction.class);

    // the model
    protected T entity;

    // model's Class
    protected Class<T> entityClass;

    // model's ClassName
    protected String entityClassName;

    // list页面显示的对象列表
    protected List<T> entities;

    public Map<String, String> getQm() {
	return qm;
    }

    public void setQm(Map<String, String> qm) {
	this.qm = qm;
    }

    protected void saveBizMessage(String message) {
	if (StringUtils.isEmpty(message)) {
	    logger.error("biz message can't empty,please check i18n config!");
	    message = "<font color='red'>Undefine message,please contact to Admin!</font>";
	}
	HttpServletRequest request = ServletActionContext.getRequest();
	HttpSession session = request.getSession();
	logger.debug("save message:" + message);
	session.setAttribute("message", message);
    }

    protected void saveBizError(String error) {
	HttpServletRequest request = ServletActionContext.getRequest();
	HttpSession session = request.getSession();
	logger.debug("save error:" + error);
	error = error.replaceAll("'", "’");
	logger.debug("save error after replace:" + error);
	session.setAttribute("error", error);
    }

    @SuppressWarnings("unchecked")
    public BaseAction() {
	super();
	// 通过反射取得Entity的Class.
	try {
	    entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	    entityClassName = entityClass.getSimpleName();
	} catch (RuntimeException e) {
	    // logger.error("error detail:",e);
	}

    }

    protected Object findBean(String beanId) {
	return AppServiceHelper.findBean(beanId);
    }

    /**
     * 实现ModelDriven接口方法，返回模型对象
     * 
     * @see ModelDriven
     */
    public T getModel() {
	return entity;
    }

    /**
     * 实现Preparable接口方法，准备填充实体对象
     * 
     * @see Preparable
     */
    public void prepare() throws Exception {
		if (entityClass == null) {
		    return;
		}
		if (getSid() != null) {
		    entity = getBaseService().findByPrimaryKey(getSid());
		    if (entity == null)
			throw new IllegalArgumentException("id not exist");
		} else {
		    entity = entityClass.newInstance();
		    //为当前新增对象的班时班次赋默认值
		    fillingShiftAndTeamTimeAttribute(entity);
		}
    }
    
    /**
     * 利用反射检测对象中是否存在班时班次
     * 因登录时可能带相应的班时班次，故此处进行提取并为当前对象的班时班次赋默认值
     */
    public void fillingShiftAndTeamTimeAttribute(Object object){
    	//获取当前方法集合
    	Method[] methods = object.getClass().getDeclaredMethods();
    	Object obb = null;
    	//选择调用当前集合方法
    	//此处不进行设置值转换，班时班次此处只处理String类型
    	try{
    		if(LoginUtil.getShift() != null && !LoginUtil.getShift().equals("NA")){
		    	Method methodSetShift = object.getClass().getDeclaredMethod("setShift",String.class);
		    	methodSetShift.invoke(object,new Object[]{String.valueOf(LoginUtil.getShift())});
    		}
	    	if(LoginUtil.getTeamTime() != null && !LoginUtil.getTeamTime().equals("NA")){
		    	Method methodSetTeamTime = object.getClass().getDeclaredMethod("setTeamTime",String.class);
		    	methodSetTeamTime.invoke(object,new Object[]{String.valueOf(LoginUtil.getTeamTime())});
	    	}
	    	
    	} catch (java.lang.NoSuchMethodException e){
    		logger.info("No Such Method Of setShift() Or setTeamTime() Thrownable By BaseAction!");
    	} catch (IllegalArgumentException e) {
    		logger.info("IllegalArgumentException By BaseAction  for setShift() Or setTeamTime() !");
		} catch (IllegalAccessException e) {
			logger.info("IllegalAccessException By BaseAction  for setShift() Or setTeamTime() !");
		} catch (InvocationTargetException e) {
			logger.info("InvocationTargetException By BaseAction  for setShift() Or setTeamTime() !");
		}
    	
    }

    /**
     * 在调用Serivce的分页方法之前，预处理分页相关参数
     * 
     * @param request
     * @return
     * @throws Exception
     * @author xiali2
     * @since 2008-9-16
     */
    protected Map<String, Object> preparePageParams(HttpServletRequest request) throws Exception {
	String query = request.getQueryString();
	String pageURL = request.getServletPath();
	if (query != null && query.length() > 0) {
	    pageURL += "?" + query;
	}
	request.setAttribute("contextURL", URLEncoder.encode(pageURL, "UTF-8"));
	logger.debug("pageURL=" + request.getContextPath() + pageURL);
	request.setAttribute("pageURL", request.getContextPath() + pageURL);
	Map<String, Object> params = new HashMap<String, Object>();
	Set<Map.Entry<String, String>> p = qm.entrySet();
	for (Map.Entry<String, String> me : p) {
	    String name = me.getKey();
	    String value = me.getValue();
	    if (StringUtils.isNotEmpty(value)) {
		params.put(name, value);
	    }
	}
	logger.debug("params=" + params);
	int pageNo = 1;
	if (!StringUtils.isEmpty((String) qm.get(PARAMS_KEY_PAGE_NO))) {
	    try {
		pageNo = Integer.parseInt((String) qm.get(PARAMS_KEY_PAGE_NO));
	    } catch (RuntimeException e) {
	    }
	}
	params.put(PARAMS_KEY_PAGE_NO, new Integer(pageNo));
	int limit = PAGE_LIMIT;
	if (!StringUtils.isEmpty((String) qm.get(PARAMS_KEY_PAGE_LIMIT))) {
	    try {
		limit = Integer.parseInt((String) qm.get(PARAMS_KEY_PAGE_LIMIT));
	    } catch (RuntimeException e) {
	    }
	}
	params.put(PARAMS_KEY_PAGE_LIMIT, new Integer(limit));
	return params;
    }

    /**
     * 分页查询方法
     * 
     * @return
     * @throws Exception
     */
    public String findByPage() throws Exception {
	HttpServletRequest request = ServletActionContext.getRequest();
	Map<String, Object> params = this.preparePageParams(request);
	Page<T> page = getBaseService().findByPage(params, (Integer) params.get(PARAMS_KEY_PAGE_NO),
		(Integer) params.get(PARAMS_KEY_PAGE_LIMIT));
	entities = page.getResultList();
	request.setAttribute(PARAMS_KEY_PAGE_OBJECT, page);
	onFindByPage(request);
	return SUCCESS;
    }

    /**
     * 定义一个回调方法，默认基类没有任何实现，子类根据需要覆写该方法实现为findByPage方法补充额外数据 主要用于分页页面初始化用于转移相关的对象
     * 
     * @param request
     * @author xiali2
     * @since 2008-7-31
     */
    protected void onFindByPage(HttpServletRequest request) {

    }

    /**
     * 列表显示所有记录(考虑显示效率问题一般少用，而是采用分页显示方式)
     * 
     * @return
     * @throws Exception
     */
    public String list() throws Exception {
	entities = getBaseService().findAll();
	return SUCCESS;
    }

    /**
     * 显示新增或修改的表单
     */
    @Override
    public String input() throws Exception {
	return INPUT;
    }

    /**
     * 新增或修改对象保存 如果页面没有主键参数值，则表示是创建对象；如果页面有主键参数值，表示更新对象
     * 
     * @return
     * @throws Exception
     */
    public String save() throws Exception {
	logger.debug("entity=" + entity);
	    HttpServletRequest request = ServletActionContext.getRequest();
	    if (getSid() == null) {
		entity.setCreatedBy(LoginUtil.getUpcUserPin());
		getBaseService().insert(entity);
		request.setAttribute("method", "insert");
		saveBizMessage(getText("tips.insert.success", new String[] { String.valueOf(entity.getSid()) }));
	    } else {
		try{
		entity.setUpdatedBy(LoginUtil.getUpcUserPin());
		getBaseService().update(entity);
		request.setAttribute("method", "update");
		saveBizMessage(getText("tips.update.success", new String[] { String.valueOf(entity.getSid()) }));
		}catch (Exception e) {
               return SUCCESS;
		}
	    }
	    return SUCCESS;
    }

    /**
     * 删除对象 传入待删除对象参数的数组，然后调用Service层批量删除方法
     * 
     * @return
     * @throws Exception
     */
    public String delete() throws Exception {
	try{
	HttpServletRequest request = ServletActionContext.getRequest();
	String[] sids = request.getParameterValues("_sid");
	Collection<T> deleteEntities = new HashSet<T>();
	if (sids != null && sids.length > 0) {
	    for (String sid : sids) {
		T entity = getBaseService().findByPrimaryKey(new Long(sid));
		if (entity == null){
		    return "concurrentModify";
		}
		deleteEntities.add(entity);
	    }
	}
	getBaseService().deleteAll(deleteEntities);
	request.setAttribute("method", "delete");
	saveBizMessage(getText("tips.delete.success", new String[] { String.valueOf(deleteEntities.size()) }));
	return SUCCESS;}catch (Exception e) {
	    return "globalError";
	}
    }

    /**
     * 默认执行函数
     */
    @Override
    public String execute() throws Exception {
	return SUCCESS;
    }

    /**
     * 向显示页面返回对象列表.
     */
    public List<T> getEntities() {
	return entities;
    }

    /**
     * 取得Service接口对象 默认以实体对象类名的前缀小写形式+Service获取对应的Service对象实例 详见初始化构造函数
     */
    @SuppressWarnings("unchecked")
    protected BaseService<T> getBaseService() {
	BaseService<T> baseService = (BaseService<T>) findBean(StringUtils.uncapitalize(entityClassName) + "Service");
	logger.debug("baseService=" + baseService);
	return baseService;
    }

    /**
     * 从参数中取得主键参数值,可在子类重载
     */
    protected Long getSid() {
	HttpServletRequest request = ServletActionContext.getRequest();
	String sid = request.getParameter("sid");
	if (StringUtils.isNotEmpty(sid)) {
	    return new Long(sid);
	} else {
	    return null;
	}
    }

    /**
     * 获取request对象
     * 
     * @return
     */
    protected HttpServletRequest getRequest() {
	return ServletActionContext.getRequest();
    }

    /**
     * 获取response对象
     * 
     * @return
     */
    protected HttpServletResponse getResponse() {
	return ServletActionContext.getResponse();
    }

    /**
     * 获取ValueStack对象
     * 
     * @return
     */
    protected ValueStack getValueStack() {
	ActionContext ac = ActionContext.getContext();
	return ac.getValueStack();
    }

}
